﻿using System.Text;
using Shop.Model.Attr;
using Shop.Model.AttrTemplate;
using Shop.Model.Category;
using Shop.Model.FrontCategory;
using Shop.Model.SpecGroup;
using Shop.RemoteModel.AdvertPlace.Model;
using Shop.RemoteModel.AttrTemplate.Model;
using Shop.RemoteModel.Category.Model;
using Shop.RemoteModel.FrontCategory.Model;
using Shop.RemoteModel.Goods.Model;
using Shop.RemoteModel.GoodsSku.Model;
using Shop.RemoteModel.GoodsSpec.Model;
using Shop.RemoteModel.PageModule.ModuleConfig;
using WeDonekRpc.Helper;

namespace Shop.Service.Helper
{
    internal static class LinqHelper
    {
        public static List<long> LoadPlaceId ( this PageModuleConfig config )
        {
            List<long> placeId = [];
            if ( config.ModuleName == "imgWall" || config.ModuleName == "skuRecommend" || config.ModuleName == "skuTabs" )
            {
                return placeId;
            }
            if ( config.ModuleName == "rollAdvert" )
            {
                if ( config.RollAdvert != null )
                {
                    placeId.Add(config.RollAdvert.PlaceId);
                }
            }
            else if ( config.ModuleName == "imgAdvert" && config.ImgAdvert != null )
            {
                placeId.Add(config.ImgAdvert.PlaceId);
            }
            else if ( config.ModuleName == "treeAdvert" && config.TreeAdvert != null )
            {
                TreeAdvertImgConfig tree = config.TreeAdvert;
                if ( tree.Top != null )
                {
                    placeId.Add(tree.Top.PlaceId);
                }
                if ( tree.Bottom != null )
                {
                    placeId.Add(tree.Bottom.PlaceId);
                }
                if ( tree.Left != null )
                {
                    placeId.Add(tree.Left.PlaceId);
                }
            }
            return placeId;
        }
        public static Out[] Convert<T, Out> ( this T[] array, Predicate<T> find, Converter<T, Out[]> converter )
        {
            List<Out> list = new List<Out>(array.Length);
            foreach ( T val in array )
            {
                if ( find(val) )
                {
                    list.AddRange(converter(val));
                }
            }
            return list.ToArray();
        }
        public static Out[] ConvertAll<T, Out> ( this T[] array, Converter<T, Out[]> converter )
        {
            List<Out> list = new List<Out>(array.Length);
            foreach ( T val in array )
            {
                list.AddRange(converter(val));
            }
            return list.ToArray();
        }
        private static bool _TryGetFileId ( string fileUri, out long id )
        {
            if ( fileUri.IsNull() )
            {
                id = 0;
                return false;
            }
            id = long.Parse(Path.GetFileNameWithoutExtension(fileUri));
            return true;
        }
        public static long[] GetDropFileId ( this PageModuleConfig config )
        {
            if ( config == null || config.ModuleName.IsNull() )
            {
                return null;
            }
            List<long> ids = [];
            if ( config.ModuleName == "imgWall" )
            {
                if ( _TryGetFileId(config.ImgWall.ImgSrc, out long id) )
                {
                    ids.Add(id);
                }
            }
            else if ( config.ModuleName == "skuRecommend" )
            {
                if ( _TryGetFileId(config.Recommend.TitleImg, out long id) )
                {
                    ids.Add(id);
                }
            }
            else if ( config.ModuleName == "menus" )
            {
                config.Menus.ForEach(c =>
                {
                    if ( _TryGetFileId(c.Icon, out long id) )
                    {
                        ids.Add(id);
                    }
                });
            }
            return ids.ToArray();
        }
        public static string GetImgShow ( this PlaceImageSet set, short imgNum )
        {
            if ( set == null || set.IsNull() )
            {
                return "允许上传" + imgNum + "张广告图。";
            }
            StringBuilder str = new StringBuilder();
            if ( !set.Ratio.IsNull() )
            {
                _ = str.AppendFormat("图片比例: {0}:{1}，", set.Ratio[0], set.Ratio[1]);
            }
            if ( set.MinWidth.HasValue )
            {
                _ = str.AppendFormat("最小宽度: {0}，", set.MinWidth.Value);
            }
            if ( set.MinHeight.HasValue )
            {
                _ = str.AppendFormat("最小高度: {0}，", set.MinHeight.Value);
            }
            if ( set.MaxWidth.HasValue )
            {
                _ = str.AppendFormat("最大宽度: {0}，", set.MaxWidth.Value);
            }
            if ( set.MaxHeight.HasValue )
            {
                _ = str.AppendFormat("最大高度: {0}，", set.MaxHeight.Value);
            }
            _ = str.AppendFormat("允许上传{0}张广告图。", imgNum);
            return str.ToString();
        }
        public static string ToSpecKey ( this long[] specId )
        {
            return string.Join(',', specId.OrderBy(a => a)).GetMd5();
        }
        public static GoodsAttr[] ToTree ( this GoodsAttrDto[] attrs )
        {
            return attrs.Convert(c => c.ParentId == 0, a => new GoodsAttr
            {
                Name = a.Name,
                Value = a.Value,
                IsDir = a.IsDir,
                Attrs = _GetAttrs(a, attrs)
            });
        }
        private static GoodsAttr[] _GetAttrs ( GoodsAttrDto attr, GoodsAttrDto[] attrs )
        {
            return attrs.Convert(c => c.ParentId == attr.Id, a => new GoodsAttr
            {
                Name = a.Name,
                Value = a.Value,
                IsDir = a.IsDir,
                Attrs = _GetAttrs(a, attrs)
            });
        }
        private static Dictionary<long, string> _GetSpecSku ( this GoodsSpecGroup[] groups )
        {
            Dictionary<long, string> specs = [];
            groups.ForEach(c =>
            {
                c.Spec.ForEach(s =>
                {
                    specs.Add(s.Id, c.GroupName + ":" + s.SpecName);
                });
            });
            return specs;
        }
        private static void _FormatSku ( List<GoodsSpecSku> skus, GoodsSpecGroup[] groups, int index, Span<long> spacId )
        {
            int next = index + 1;
            foreach ( GoodsSpec spec in groups[index].Spec )
            {
                if ( next >= spacId.Length )
                {
                    long[] ids = spacId.ToArray();
                    ids[index] = spec.Id;
                    skus.Add(new GoodsSpecSku
                    {
                        SpecId = ids
                    });
                }
                else
                {
                    spacId[index] = spec.Id;
                    _FormatSku(skus, groups, next, spacId);
                }
            }
        }
        public static Dictionary<string, GoodsSpecState> GetSpecState ( this GoodsSpecGroup[] groups, Dictionary<string, bool> state )
        {
            int gLen = groups.Length;
            List<GoodsSpecSku> skus = new List<GoodsSpecSku>(20);
            groups[0].Spec.ForEach(c =>
            {
                Span<long> ids = new Span<long>(new long[gLen]);
                ids[0] = c.Id;
                _FormatSku(skus, groups, 1, ids);
            });
            skus.ForEach(c =>
            {
                c.SpecKey = string.Join(',', c.SpecId.OrderBy(a => a)).GetMd5();
            });
            return skus.ToDictionary(a => a.SpecKey, a => new GoodsSpecState
            {
                IsEnable = state.GetValueOrDefault(a.SpecKey, true),
                SpecId = a.SpecId
            });
        }
        public static GoodsSpecSku[] GetSpecSku ( this GoodsSpecGroup[] groups )
        {
            Dictionary<long, string> specName = _GetSpecSku(groups);
            int gLen = groups.Length;
            List<GoodsSpecSku> skus = new List<GoodsSpecSku>(20);
            groups[0].Spec.ForEach(c =>
            {
                Span<long> ids = new Span<long>(new long[gLen]);
                ids[0] = c.Id;
                _FormatSku(skus, groups, 1, ids);
            });
            skus.ForEach(c =>
            {
                c.SpecKey = string.Join(',', c.SpecId.OrderBy(a => a)).GetMd5();
                c.Name = c.SpecId.ConvertAll(a => specName[a]);
            });
            return skus.ToArray();
        }

        public static string GetSpecsShow ( this SpecDto[] spec )
        {
            return string.Join('|', spec.Select(a => a.SpecName));
        }
        public static AttrTemplateTree[] GetTree ( this AttrTemplateDto[] list )
        {
            return list.Convert(a => a.ParentId == 0, a =>
            {
                AttrTemplateTree tree = new AttrTemplateTree
                {
                    Id = a.Id,
                    IsEnable = a.IsEnable,
                    Name = a.Name,
                    Sort = a.Sort,
                    DefValue = a.DefValue,
                };
                tree.Children = _GetChildren(tree, list);
                return tree;
            });
        }
        private static AttrTemplateTree[] _GetChildren ( AttrTemplateTree parent, AttrTemplateDto[] dtos )
        {
            AttrTemplateTree[] child = dtos.Convert(a => a.ParentId == parent.Id, a =>
            {
                AttrTemplateTree tree = new AttrTemplateTree
                {
                    Id = a.Id,
                    IsEnable = a.IsEnable,
                    Name = a.Name,
                    Sort = a.Sort,
                    DefValue = a.DefValue,
                };
                tree.Children = _GetChildren(tree, dtos);
                return tree;
            });
            if ( !child.IsNull() )
            {
                parent.IsDir = true;
            }
            return child;
        }
        public static CategoryTree[] GetTree ( this CategoryDto[] list, long prtId )
        {
            return list.Convert(a => a.ParentId == prtId, a => new CategoryTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                Children = _GetChildren(a, list)
            });
        }
        public static CategoryFullTree[] GetTree ( this GoodsCategory[] dtos )
        {
            return dtos.Convert(a => a.ParentId == 0, a => new CategoryFullTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                IsEnable = a.IsEnable,
                Sort = a.Sort,
                Children = _GetChildren(a, dtos)
            });
        }
        private static CategoryTree[] _GetChildren ( CategoryDto parent, CategoryDto[] dtos )
        {
            return dtos.Convert(a => a.ParentId == parent.Id, a => new CategoryTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                Children = _GetChildren(a, dtos)
            });
        }
        private static CategoryFullTree[] _GetChildren ( GoodsCategory parent, GoodsCategory[] dtos )
        {
            return dtos.Convert(a => a.ParentId == parent.Id, a => new CategoryFullTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                IsEnable = a.IsEnable,
                Sort = a.Sort,
                Children = _GetChildren(a, dtos)
            });
        }

        public static FrontCategoryTree[] GetTree ( this FrontCategoryDto[] list )
        {
            return list.Convert(a => a.ParentId == 0, a => new FrontCategoryTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                Icon = a.Icon,
                Children = _GetChildren(a, list)
            });
        }
        public static FrontCategoryFullTree[] GetTree ( this FrontCategoryData[] dtos, Dictionary<long, BindCategory[]> category )
        {
            return dtos.Convert(a => a.ParentId == 0, a => new FrontCategoryFullTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                IsEnable = a.IsEnable,
                Sort = a.Sort,
                Icon = a.Icon,
                Category = category.GetValueOrDefault(a.Id),
                Children = _GetChildren(a, dtos, category)
            });
        }
        private static FrontCategoryTree[] _GetChildren ( FrontCategoryDto parent, FrontCategoryDto[] dtos )
        {
            return dtos.Convert(a => a.ParentId == parent.Id, a => new FrontCategoryTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                Icon = a.Icon,
                Children = _GetChildren(a, dtos)
            });
        }
        private static FrontCategoryFullTree[] _GetChildren ( FrontCategoryData parent, FrontCategoryData[] dtos, Dictionary<long, BindCategory[]> category )
        {
            return dtos.Convert(a => a.ParentId == parent.Id, a => new FrontCategoryFullTree
            {
                Id = a.Id,
                CategoryName = a.CategoryName,
                IsEnable = a.IsEnable,
                Sort = a.Sort,
                Icon = a.Icon,
                Category = category.GetValueOrDefault(a.Id),
                Children = _GetChildren(a, dtos, category)
            });
        }
    }
}
